#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>

int create_udp_socket(char *ip, int port)
{
    signal(SIGPIPE, SIG_IGN);

    int sockfd;
    int sockaddr_len;

    struct in_addr server_ip;
    struct sockaddr_in server_addr;
    // 1、socket函数创建套接字 -->  文件描述符  UDP
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket create failed!\n");
        exit(1);
    }
    printf("socket create Success! %d\n", sockfd);

    int reuse = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

    //??为什么要绑定IP和端口号？接受客户端的连接，就需要确定服务器的IP和端口号
    // 2、bind：给套接字绑定IP地址和端口号
    // 初始化struct sockadd_in变量；

    // inet_pton(AF_INET, ip, (void *)&server_ip);
    // server_addr.sin_family = AF_INET;   // IPV4
    // server_addr.sin_addr = server_ip;   // IP
    // server_addr.sin_port = htons(port); // h:host to n:net

    // if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0)
    // {
    //     perror("bind ip & port failed!");
    //     exit(1);
    // }
    // printf("bind Success ip = %s port = %d\n", ip, port);

    return sockfd;
}
void setnonblock(int sockfd)
{
    int flags = fcntl(sockfd, F_GETFL);
    flags = flags | O_NONBLOCK;
    fcntl(sockfd, F_SETFL, flags);
}

int main(int argc, char **argv)
{
    if (argc != 3)
    {
        printf("Please input server bind ip and port!\n");
        exit(1);
    }

    int sockfd;
    int r_len;
    int confd;
    socklen_t sockaddr_len;
    char message[1024] = {0};
    char client_ip[INET_ADDRSTRLEN];
    struct sockaddr_in client_addr;

    struct sockaddr_in server_addr;
    struct in_addr server_ip;
    inet_pton(AF_INET, argv[1], (void *)&server_ip);
    server_addr.sin_family = AF_INET;            // IPV4
    server_addr.sin_addr = server_ip;            // IP
    server_addr.sin_port = htons(atoi(argv[2])); // h:host to n:net

    sockfd = create_udp_socket(argv[1], atoi(argv[2]));
    setnonblock(sockfd);
    while (1)
    {
        memset(message, 0, sizeof(message));
        printf("Pleasse input message:\n");
        scanf("%s", message);
        sendto(sockfd, message, strlen(message), 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
        memset(message, 0, sizeof(message));
        sockaddr_len = sizeof(struct sockaddr);
        r_len = recvfrom(sockfd, message, sizeof(message) - 1, 0, (struct sockaddr *)&client_addr,
                         &sockaddr_len);
        if (r_len < 0)
        {
            perror("udp recvfrom error!");
            exit(1);
        }

        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
        printf("%s:%d recv message = %s\n", client_ip, client_addr.sin_port, message);
    }
}